#pragma once

// 引入所需的头文件
#include "index.hpp"  // 索引库
#include "util.hpp"   // 工具库
#include "log.hpp"    // 日志库
#include <algorithm>  // C++ 标准库算法
#include <unordered_map>       // 哈希表容器
#include <jsoncpp/json/json.h> // JSON处理库

// 定义命名空间ns_searcher
namespace ns_searcher {
    // 定义用于打印的倒排元素结构体
    struct InvertedElemPrint {
        uint64_t doc_id; // 文档ID
        int weight; // 权重
        std::vector<std::string> words; // 包含的关键字
        InvertedElemPrint() : doc_id(0), weight(0) {} // 默认构造函数
    };

    // 定义搜索引擎类Searcher
    class Searcher {
    private:
        // 索引对象指针
        ns_index::Index *index;

    public:
        // 构造函数
        Searcher() {}
        // 析构函数
        ~Searcher() {}

        // 初始化搜索引擎
        void InitSearcher(const std::string &input) {
            // 获取或创建索引对象
            index = ns_index::Index::GetInstance();
            LOG(NORMAL, "获取index单例成功...");
            // 根据索引对象建立索引
            index->BuildIndex(input);
            LOG(NORMAL, "建立正排和倒排索引成功...");
        }

        // 执行搜索查询,query: 搜索关键字json_string: 返回给用户浏览器的搜索结果
        void Search(const std::string &query, std::string *json_string) {
            // 对查询关键字进行分词
            std::vector<std::string> words;
            ns_util::JiebaUtil::CutString(query, &words);

            // 准备用于存储搜索结果的结构
            std::unordered_map<uint64_t, InvertedElemPrint> tokens_map;
            std::vector<InvertedElemPrint> inverted_list_all;

            // 遍历分词结果，查询索引并合并结果
            for (std::string word : words) {
                boost::to_lower(word); // 转换为小写
                ns_index::InvertedList *inverted_list = index->GetInvertedList(word);
                if (inverted_list) {
                    for (const auto &elem : *inverted_list) {
                        auto &item = tokens_map[elem.doc_id]; // 获取或创建对应doc_id的InvertedElemPrint
                        item.doc_id = elem.doc_id;
                        item.weight += elem.weight;
                        item.words.push_back(elem.word);
                    }
                }
            }

            // 将合并后的结果添加到inverted_list_all
            for (const auto &item : tokens_map) {
                inverted_list_all.push_back(std::move(item.second));
            }

            // 根据权重降序排序搜索结果
            std::sort(inverted_list_all.begin(), inverted_list_all.end(),
                      [](const InvertedElemPrint &e1, const InvertedElemPrint &e2) {
                          return e1.weight > e2.weight;
                      });

            // 构建JSON格式的搜索结果
            Json::Value root;
            for (auto &item : inverted_list_all) {
                ns_index::DocInfo *doc = index->GetForwardIndex(item.doc_id);
                if (doc) {
                    Json::Value elem;
                    elem["title"] = doc->title;// 文档标题
                    elem["desc"] = GetDesc(doc->content, item.words[0]); // 获取描述
                    elem["url"] = doc->url; // 文档URL
                    elem["id"] = (int)item.doc_id; // 文档ID
                    elem["weight"] = item.weight; // 权重

                    root.append(elem);
                }
            }

            // 将JSON对象转换为字符串
            Json::FastWriter writer;
            *json_string = writer.write(root);
        }

        // 获取文档描述的辅助函数
        std::string GetDesc(const std::string &html_content, const std::string &word) {
            // 查找word在html_content中的首次出现位置
            auto iter = std::search(html_content.begin(), html_content.end(),
                                 word.begin(), word.end(), [](int x, int y) {
                                     return (std::tolower(x) == std::tolower(y));
                                 });
            if (iter == html_content.end()) {
                return "None1";
            }
            int pos = std::distance(html_content.begin(), iter);

            // 确定描述的起始和结束位置
            int start = pos - 50;
            int end = pos + 100;
            if (start < 0) start = 0;
            if (end > (int)html_content.size()) end = (int)html_content.size();

            // 截取描述内容并返回
            std::string desc = html_content.substr(start, end - start);
            desc += "...";
            return desc;
        }
    };
}